// @include "../code/Namespace.js"
// @include "../code/Function.js"
// @include "../code/Tmpl.js"
/**
 * @fileOverview aop实现工具类
 * 
 * @version qinglan_element 1.0
 * @static
 * @author wxq wxqqh@qq.com
 */
/**
 * 命名空间
 * 
 * @namespace
 * @type Object
 */
window.qinglan = window.qinglan || {};
/**
 * aop命名空间<br/>
 * 
 * @namespace
 * @type Object
 */
qinglan.Aop = qinglan.Aop || {};
/**
 * 添加aop支持的方法的索引
 * 
 * @private
 * @static
 * @type Number
 */
qinglan.Aop.__methodId = 1;
/**
 * 添加aop支持的通知的索引
 * 
 * @private
 * @static
 * @type Number
 */
qinglan.Aop.__adviceId = 1;
/**
 * aop支持缓存
 * 
 * @private
 * @static
 * @type Object
 */
qinglan.Aop.__AdvicePool = {};
/**
 * AOP 模式,设定为需要判断输入状态机(前一状态机)的状态
 * 
 * @public
 * @static
 * @type String
 */
qinglan.Aop.ALLOW_MODE_IN = 'in';
/**
 * AOP 模式,设定为需要判断输出状态机(当前状态机)的状态
 * 
 * @public
 * @static
 * @type String
 */
qinglan.Aop.ALLOW_MODE_OUT = 'out';
/**
 * aop方向，设定为方法执行之前
 * 
 * @type String
 */
qinglan.Aop.ALLOW_DIRECTION_BEFORE = 'before';
/**
 * aop方向，设定为方法执行之后
 * 
 * @type String
 */
qinglan.Aop.ALLOW_DIRECTION_AFTER = 'after';
/**
 * 进行状态机验证的断言
 * 
 * @public
 * @static
 * @type Object
 */
qinglan.Aop.ALLOW_ASSERT_EQUATION = {
	/**
	 * 默认的验证函数
	 * 
	 * @public
	 * @static
	 * @type Function
	 */
	NORMAL : qinglan.Function.emptyFun,
	/**
	 * 默认的验证结果,为真
	 * 
	 * @public
	 * @static
	 * @type Boolean
	 */
	TRUE : true,
	/**
	 * 默认的验证结果,为假
	 * 
	 * @public
	 * @static
	 * @type Boolean
	 */
	FALSE : false
};

/**
 * 添加aop支持
 * 
 * @param {String}
 *            methodNamespace 需要添加aop支持的方法的命名空间
 * @param {Function}
 *            Advice 需要添加的通知的方法
 * @param {String}
 *            direction aop验证方向 <br/>
 *            <b>qinglan.Aop.ALLOW_DIRECTION_BEFORE(目标函数执行前)</b> 或者
 *            <b>qinglan.Aop.ALLOW_DIRECTION_AFTER(目标函数执行后)</b>
 * @param {String}
 *            mode aop验证模式 <br/><b>qinglan.Aop.ALLOW_MODE_IN(判断advice前一状态)</b>
 *            或者 <b>qinglan.Aop.ALLOW_MODE_OUT(判断当前advice输出状态)</b>
 * @param {Object}{Function}
 *            assert aop验证断言
 * @public
 * @function
 */
qinglan.Aop.addAdvice = function(methodNamespace, advice, direction, mode,
		assert) {
	var aop_init = qinglan.Aop._initAdviceSupport(methodNamespace, advice);
	var nsAdvice = qinglan.Namespace.generate(aop_init.method.__aop_support_id,
			direction);
	var ns = qinglan.Namespace.get(nsAdvice, qinglan.Aop.__AdvicePool);
	if (!!ns) {
		ns[advice.__aop_advice_id] = {
			'advice' : aop_init.advice,
			'mode' : mode,
			'assert' : assert
		};
		qinglan.Aop._bindAop(methodNamespace, aop_init.method);
	} else {
		qinglan.Debug.error('The function :[' + methodNamespace
						+ '] init aop support Error!!');
		return false;
	}
};
/**
 * 初始化aop支持
 * 
 * @param {String}
 *            methodNamespace 需要添加aop支持的方法的命名空间
 * @param {Function}
 *            Advice 需要添加的通知的方法
 * @private
 * @function
 */
qinglan.Aop._initAdviceSupport = function(methodNamespace, advice) {
	var method = qinglan.Namespace.get(methodNamespace);// 得到命名空间所指向的实体
	// 对实体添加aop支持id,只执行一次
	!method.__aop_support_id
			&& (method.__aop_support_id = qinglan.Aop.__methodId++);
	// 对实体添加aop初始化标志,只执行一次
	!method.__aop_support_init && (method.__aop_support_init = false);
	// 对实体添加aop绑定标志,只执行一次
	!method.__aop_support_bind && (method.__aop_support_bind = false);
	// 对通知添加aop通知id,只执行一次
	!advice.__aop_advice_id
			&& (advice.__aop_advice_id = qinglan.Aop.__adviceId++);
	// 进行命名空间初始化
	if (!method.__aop_support_init) {
		qinglan.Aop.__AdvicePool[method.__aop_support_id] = {
			before : {},
			after : {},
			origin : method
		};
		method.__aop_support_init = true;
	};
	return {
		'method' : method,
		'advice' : advice
	};
};

qinglan.Aop._bindAop = function(methodNamespace, method) {
	var flag = true;
	/**
	 * 进行aop调用
	 */
	var _doAop = function() {
		/**
		 * 记录当前返回值
		 */
		var currentReturn = true;
		/**
		 * 进行断言判断
		 * 
		 * @param {Object}
		 *            assert 断言
		 * @param {Object}
		 *            returnValue 需要断言对象，为函数返回值
		 */
		var doAssert = function(assert, returnValue) {
			if (qinglan.Type.isFunction(assert)) {
				return assert.call(null, returnValue);
			} else {
				return assert === returnValue;
			}
		};
		/**
		 * 记录断言失败结果
		 * 
		 * @param {Object}
		 *            assert 断言
		 * @param {Object}
		 *            returnValue 需要断言对象，为函数返回值
		 * @param {String}
		 *            direction aop验证方向
		 * @param {String}
		 *            mode aop验证模式
		 */
		var logAssert = function(assert, returnValue, direction, mode) {
			qinglan.Debug.info(qinglan.Tmpl.smTmpl('Do {direction} {mode} Assert to assert :[{assert}] & currentReturn :[{returnValue}] ',{
												'direction' : direction,
												'mode' : mode,
												'assert' : assert,
												'returnValue' : returnValue
											}));
		};
		/**
		 * 进行aop执行通知
		 * 
		 * @param {String}
		 *            direction aop验证方向
		 */
		var doAdvice = function(direction, args) {
			var adviceChain = qinglan.Aop.__AdvicePool[method.__aop_support_id][direction];
			for (var id in adviceChain) {
				var advice = adviceChain[id];
				if (advice.mode == 'in') {// in 模式，先对输入前状态进行判断,再执行函数
					if (doAssert(advice.assert, currentReturn)) {
						currentReturn = advice.advice.apply(this, args);
					} else {
						logAssert(advice.assert, currentReturn, direction,
								advice.mode);
						flag = false;
						break;

					}
				} else {// out模式，执行函数，对当前函数输出状态进行判断
					currentReturn = advice.advice.apply(this, args);
					if (!doAssert(advice.assert, currentReturn)) {
						logAssert(advice.assert, currentReturn, direction,
								advice.mode);
						flag = false;
						break;
					}
				}
			}
		};
		var origin = qinglan.Aop.__AdvicePool[method.__aop_support_id].origin;
		// 开始执行AOP
		doAdvice.call(origin, 'before', arguments);// Before
		if (flag && currentReturn) {
			originReturn = origin.apply(this, arguments);
			currentReturn = originReturn;
			doAdvice.call(origin, 'after', arguments);// After
			if (!flag) {
				 qinglan.Debug.info('AOP Do After Advice Failed !!');
				return false;
			}
			return originReturn;
		} else {
			qinglan.Debug.info('AOP Do Before Advice Failed !!');
			return false;
		}
	};
	var ns = qinglan.Namespace.create(methodNamespace, window, true);
	if (!ns.instance[ns.key].__aop_support_bind) {// 就行AOP绑定
		var aop_support_id = ns.instance[ns.key].__aop_support_id;
		var aop_support_init = ns.instance[ns.key].__aop_support_init;
		var aop_support_bind = ns.instance[ns.key].__aop_support_bind;
		ns.instance[ns.key] = function() {
			_doAop.apply(this, arguments);
		};
		ns.instance[ns.key].__aop_support_id = aop_support_id;
		ns.instance[ns.key].__aop_support_init = aop_support_init;
		ns.instance[ns.key].__aop_support_bind = true;
	}
};
/**
 * 刪除aop通知
 * 
 * @param {String}
 *            methodNamespace 需要添加aop支持的方法的命名空间
 * @param {Function}
 *            Advice 需要添加的通知的方法
 * @param {String}
 *            direction aop验证方向
 * @param {String}
 *            mode aop验证模式
 * @public
 * @function
 */
qinglan.Aop.removeAdvice = function(methodNamespace, advice, direction) {
	var method = qinglan.Namespace.get(methodNamespace);// 得到命名空间所指向的实体
	try {
		delete qinglan.Aop.__AdvicePool[method.__aop_support_id][direction][advice.__aop_advice_id];
	} catch (e) {
		qinglan.Aop.__AdvicePool[aop_support_id][direction][advice.__aop_advice_id] = function() {
			return true;
		};
		qinglan.Debug.info('The action of "removeAdvice" the method:['+ methodNamespace + '] & advice :[' + advice+ '] & direction :[' + direction + ']failed!!');
	}

};
/**
 * 删除命名空间的所有添加的通知
 * 
 * @param {String}
 *            methodNamespace 需要添加aop支持的方法的命名空间
 * @public
 * @function
 */
qinglan.Aop.clearAllAdvice = function(methodNamespace) {
	var method = qinglan.Namespace.get(methodNamespace);// 得到命名空间所指向的实体
	var aop_support_id = method.__aop_support_id;
	try {
		delete qinglan.Aop.__AdvicePool[aop_support_id];
	} catch (e) {
		qinglan.Aop.__AdvicePool[aop_support_id] = {};
		qinglan.Debug.info('The action of "clearAllAdvice" the method:['+ methodNamespace + '] failed!!');
	}

};

/**
 * 
 * @param {String}
 *            methodNamespace 需要添加aop支持的方法的命名空间
 * @param {Function}
 *            advice 需要添加的通知的方法
 * @param {String}
 *            mode aop验证模式 <br/><b>qinglan.Aop.ALLOW_MODE_IN(判断advice前一状态)</b>
 *            或者 <b>qinglan.Aop.ALLOW_MODE_OUT(判断当前advice输出状态)</b><br/>默认是OUT
 * @param {Object}
 *            assert 断言,默认是true
 * @public
 * @function
 */
qinglan.Aop.before = function(methodNamespace, advice, mode, assert) {
	qinglan.Aop.addAdvice(methodNamespace, advice,
			qinglan.Aop.ALLOW_DIRECTION_BEFORE, mode
					|| qinglan.Aop.ALLOW_MODE_OUT, assert || true);

};
/**
 * @param {String}
 *            methodNamespace 需要添加aop支持的方法的命名空间
 * @param {Function}
 *            advice 需要添加的通知的方法
 * @param {String}
 *            mode aop验证模式 <br/><b>qinglan.Aop.ALLOW_MODE_IN(判断advice前一状态)</b>
 *            或者 <b>qinglan.Aop.ALLOW_MODE_OUT(判断当前advice输出状态)</b><br/>默认是OUT
 * @param {Object}
 *            assert 断言,默认是true
 * @public
 * @function
 */
qinglan.Aop.after = function(methodNamespace, advice, mode, assert) {
	qinglan.Aop.addAdvice(methodNamespace, advice,
			qinglan.Aop.ALLOW_DIRECTION_AFTER, mode
					|| qinglan.Aop.ALLOW_MODE_OUT, assert || true);
};